﻿<ComClass(ClsRectangle.ClassId, ClsRectangle.InterfaceId, ClsRectangle.EventsId)>
Public Class ClsRectangle

#Region "COM GUID"
    ' 这些 GUID 提供此类的 COM 标识 
    ' 及其 COM 接口。若更改它们，则现有的
    ' 客户端将不再能访问此类。
    Public Const ClassId As String = "4f5493aa-85c1-4a1d-b7ad-492907f76ce0"
    Public Const InterfaceId As String = "7e154132-5b68-4e42-88d5-1e88858f11d3"
    Public Const EventsId As String = "59dbe2cd-1202-40ba-b1f8-9ec7452489b6"
#End Region

    ' 可创建的 COM 类必须具有一个不带参数的 Public Sub New() 
    ' 否则， 将不会在 
    ' COM 注册表中注册此类，且无法通过
    ' CreateObject 创建此类。
    Public Sub New()
        MyBase.New()
    End Sub

#Region "字段和属性"

    Private _height As Double
    Public Property Height() As Double
        Get
            Return _height
        End Get
        Set(ByVal value As Double)
            _height = value
        End Set
    End Property

    Private _width As Double
    Public Property Width() As Double
        Get
            Return _width
        End Get
        Set(ByVal value As Double)
            _width = value
        End Set
    End Property

    Private _angletoXalis As Double
    Public Property AngleToXails() As Double
        Get
            Return _angletoXalis
        End Get
        Set(ByVal value As Double)
            _angletoXalis = value
        End Set
    End Property

    Private _gravitycenter As ClsPoint2d
    Public Property GravityCenter() As ClsPoint2d
        Get
            Return _gravitycenter
        End Get
        Set(ByVal value As ClsPoint2d)
            _gravitycenter = value
        End Set
    End Property

    Public ReadOnly Property Area() As Double
        Get
            Return Me.Height * Me.Width
        End Get
    End Property

    Public ReadOnly Property LeftBtm() As ClsPoint2d
        Get
            Dim v1 As New ClsVector2d, v2 As New ClsVector2d
            v1.CreatorUnitVictor2dByAngle(Me.AngleToXails + Math.PI)
            v2.CreatorUnitVictor2dByAngle(1.5 * Math.PI + Me.AngleToXails)
            Return Me.GravityCenter.Add(v1.Multiply(Me.Width * 0.5).Add(v2.Multiply(Me.Height * 0.5)))
        End Get
    End Property
    Public ReadOnly Property RightTop() As ClsPoint2d
        Get
            Dim v1 As New ClsVector2d, v2 As New ClsVector2d
            v1.CreatorUnitVictor2dByAngle(Me.AngleToXails)
            v2.CreatorUnitVictor2dByAngle(Me.AngleToXails + 0.5 * Math.PI)
            Return Me.GravityCenter.Add(v1.Multiply(Me.Width * 0.5).Add(v2.Multiply(Me.Height * 0.5)))
        End Get
    End Property
    Public ReadOnly Property LeftTop() As ClsPoint2d
        Get
            Dim v1 As New ClsVector2d, v2 As New ClsVector2d
            v1.CreatorUnitVictor2dByAngle(Me.AngleToXails + Math.PI)
            v2.CreatorUnitVictor2dByAngle(Me.AngleToXails + 0.5 * Math.PI)
            Return Me.GravityCenter.Add(v1.Multiply(Me.Width * 0.5).Add(v2.Multiply(Me.Height * 0.5)))
        End Get
    End Property
    Public ReadOnly Property RightBtm() As ClsPoint2d
        Get
            Dim v1 As New ClsVector2d, v2 As New ClsVector2d
            v1.CreatorUnitVictor2dByAngle(Me.AngleToXails)
            v2.CreatorUnitVictor2dByAngle(1.5 * Math.PI + Me.AngleToXails)
            Return Me.GravityCenter.Add(v1.Multiply(Me.Width * 0.5).Add(v2.Multiply(Me.Height * 0.5)))
        End Get
    End Property

    Public ReadOnly Property BoundingBox() As ClsRectangle
        Get
            Dim x As New List(Of Double)
            x.AddRange({Me.LeftBtm.X, Me.RightBtm.X, Me.LeftTop.X, Me.RightTop.X})
            Dim y As New List(Of Double)
            y.AddRange({Me.LeftBtm.Y, Me.RightBtm.Y, Me.LeftTop.Y, Me.RightTop.Y})
            Dim rtn As New ClsRectangle With {
                .AngleToXails = 0,
                .Height = y.Max() - y.Min(),
                .Width = x.Max() - x.Min(),
                .GravityCenter = New ClsPoint2d With {.X = (x.Max() + x.Min()) * 0.5, .Y = (y.Max() + y.Min()) * 0.5}
            }
            Return rtn
        End Get
    End Property

    Public ReadOnly Property IsSquare As Boolean
        Get
            Return Me.Width = Me.Height
        End Get
    End Property

#End Region

#Region "构造函数"
    ''' <summary>
    ''' 构造函数
    ''' </summary>
    ''' <param name="center">几何中心</param>
    ''' <param name="h">高度</param>
    ''' <param name="w">宽度</param>
    ''' <param name="ang">长边与x轴的夹角,弧度制</param>
    Public Sub Creator(center As ClsPoint2d, h As Double, w As Double, Optional ang As Double = 0)
        Me.GravityCenter = center
        Me.Height = h
        Me.Width = w
        Me.AngleToXails = ang
    End Sub
#End Region

#Region "旋转,移动,缩放,镜像"
    ''' <summary>
    ''' 移动当前矩形
    ''' </summary>
    ''' <param name="Displacement">代表移动的向量</param>
    Public Sub MoveTo(Displacement As ClsVector2d)
        Me.GravityCenter.MoveTo(Displacement)
    End Sub

    ''' <summary>
    ''' 缩放当前矩形获取新的矩形
    ''' </summary>
    ''' <param name="scaleFactor">缩放的系数，大于1表示放大，小于1表示缩小</param>
    ''' <param name="scaleCenter">缩放的基准点</param>
    ''' <returns>新的矩形 </returns>
    Public Function Scaling(ByVal scaleFactor As Double, ByVal scaleCenter As ClsPoint2d) As ClsRectangle

        Dim rtn As New ClsRectangle With {
            .GravityCenter = scaleCenter.Add(scaleCenter.GetVector2dTo(Me.GravityCenter).Multiply(scaleFactor)),
            .AngleToXails = Me.AngleToXails,
            .Height = Me.Height,
            .Width = Me.Width
        }

        Return rtn
    End Function

    ''' <summary>
    ''' 镜像当前矩形获取新的矩形
    ''' </summary>
    ''' <param name="mirrorP1"></param>
    ''' <param name="mirrorP2"></param>
    ''' <returns>新的矩形</returns>
    Public Function Mirror(ByVal mirrorP1 As ClsPoint2d, ByVal mirrorP2 As ClsPoint2d) As ClsRectangle
        Dim rtn As New ClsRectangle With {
           .GravityCenter = Me.GravityCenter.Mirror(mirrorP1, mirrorP2),
           .Height = Me.Height, .Width = Me.Width, .AngleToXails = Me.AngleToXails + Math.PI
        }
        Return rtn
    End Function

    ''' <summary>
    ''' 镜像当前矩形
    ''' </summary>
    ''' <param name="angle">旋转角度,弧度制</param>
    ''' <param name="origin">旋转中心</param>
    Public Sub RotateTo(angle As Double, origin As ClsPoint2d)
        Me.GravityCenter.Rotate(angle, origin)
        Me.AngleToXails += angle
    End Sub
#End Region

#Region "与cad转化"
    Public Function CreatefromAcadEntity(acLwPline As Object) As Boolean
        If TypeName(acLwPline) = "IAcadLWPolyline" Then
            Dim tri = acLwPline
            Dim m As New ClsACadObjectEx
            If m.LwPolyLineHasBulge(tri) = False Then
                If UBound(tri.Coordinates) - LBound(tri.Coordinates) = 7 And tri.Closed = True Then
                    Dim pts As New List(Of ClsPoint2d)
                    pts.Add(New ClsPoint2d With {.X = tri.Coordinates(0), .Y = tri.Coordinates(1)})
                    pts.Add(New ClsPoint2d With {.X = tri.Coordinates(2), .Y = tri.Coordinates(3)})
                    pts.Add(New ClsPoint2d With {.X = tri.Coordinates(4), .Y = tri.Coordinates(5)})
                    pts.Add(New ClsPoint2d With {.X = tri.Coordinates(6), .Y = tri.Coordinates(7)})
                    pts.Add(New ClsPoint2d With {.X = tri.Coordinates(0), .Y = tri.Coordinates(1)})

                    Dim vAB = pts(0).GetVector2dTo(pts(1))
                    Dim vBC = pts(1).GetVector2dTo(pts(2))
                    Dim vCD = pts(2).GetVector2dTo(pts(3))
                    Dim vDA = pts(3).GetVector2dTo(pts(0))
                    If vAB.IsPerpendicularTo(vBC) And vAB.IsParallelTo(vCD) And vAB.Length = vCD.Length Then
                        Me.GravityCenter = pts(1).GetMidPointTo(pts(2))
                        If vAB.Length > vBC.Length Then
                            Me.AngleToXails = vAB.AngelToXAxis
                            Me.Width = vAB.Length
                            Me.Height = vBC.Length
                        Else
                            Me.AngleToXails = vBC.AngelToXAxis
                            Me.Height = vAB.Length
                            Me.Width = vBC.Length
                        End If
                        Return True
                    Else
                        Return False
                    End If

                ElseIf UBound(tri.Coordinates) - LBound(tri.Coordinates) = 9 And tri.Closed = False Then
                    Dim m1 As New ClsMath
                    If m1.IsEqual(tri.Coordinates(0), tri.Coordinates(8)) And m1.IsEqual(tri.Coordinates(1), tri.Coordinates(9)) Then
                        Dim pts As New List(Of ClsPoint2d)
                        pts.Add(New ClsPoint2d With {.X = tri.Coordinates(0), .Y = tri.Coordinates(1)})
                        pts.Add(New ClsPoint2d With {.X = tri.Coordinates(2), .Y = tri.Coordinates(3)})
                        pts.Add(New ClsPoint2d With {.X = tri.Coordinates(4), .Y = tri.Coordinates(5)})
                        pts.Add(New ClsPoint2d With {.X = tri.Coordinates(6), .Y = tri.Coordinates(7)})
                        pts.Add(New ClsPoint2d With {.X = tri.Coordinates(8), .Y = tri.Coordinates(9)})

                        Dim vAB = pts(0).GetVector2dTo(pts(1))
                        Dim vBC = pts(1).GetVector2dTo(pts(2))
                        Dim vCD = pts(2).GetVector2dTo(pts(3))
                        Dim vDA = pts(3).GetVector2dTo(pts(4))
                        If vAB.IsPerpendicularTo(vBC) And vAB.IsParallelTo(vCD) And vAB.Length = vCD.Length Then
                            Me.GravityCenter = pts(1).GetMidPointTo(pts(2))
                            If vAB.Length > vBC.Length Then
                                Me.AngleToXails = vAB.AngelToXAxis
                                Me.Width = vAB.Length
                                Me.Height = vBC.Length
                            Else
                                Me.AngleToXails = vBC.AngelToXAxis
                                Me.Height = vAB.Length
                                Me.Width = vBC.Length
                            End If
                            Return True
                        Else
                            Return False
                        End If
                    Else
                        Return False
                    End If
                Else
                    Return False
                End If
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function

    Public Function ToAcadEntity(acLayout As Object) As Object
        Dim acLwPolyline As Object
        Dim listVertexs(0 To 9) As Double

        listVertexs(0) = Me.LeftBtm.X : listVertexs(1) = Me.LeftBtm.Y
        listVertexs(2) = Me.RightBtm.X : listVertexs(3) = Me.RightBtm.Y
        listVertexs(4) = Me.RightTop.X : listVertexs(5) = Me.RightTop.Y
        listVertexs(6) = Me.LeftTop.X : listVertexs(7) = Me.LeftTop.Y
        listVertexs(8) = Me.LeftBtm.X : listVertexs(9) = Me.LeftBtm.Y

        acLwPolyline = acLayout.AddLightWeightPolyline(listVertexs)
        Return acLwPolyline
    End Function
#End Region

#Region "与其它矩形对象的关系"

    ''' <summary>
    ''' 判断当前矩形是否包含其他矩形
    ''' </summary>
    ''' <param name="rec">被包含的矩形</param>
    ''' <returns>布尔类型</returns>
    Public Function Contains(rec As ClsRectangle) As Boolean
        Dim recBOb = rec.BoundingBox
        If recBOb.GravityCenter.PointRelation2Rectangle(Me) <> 点与封闭图形的位置关系.在内部 Then
            Return False
        Else
            If recBOb.LeftTop.PointRelation2Rectangle(Me) <> 点与封闭图形的位置关系.在内部 Or
                recBOb.LeftBtm.PointRelation2Rectangle(Me) <> 点与封闭图形的位置关系.在内部 Or
                recBOb.RightBtm.PointRelation2Rectangle(Me) <> 点与封闭图形的位置关系.在内部 Or
                recBOb.RightTop.PointRelation2Rectangle(Me) <> 点与封闭图形的位置关系.在内部 Then
                Return False
            Else
                Return True
            End If
        End If
    End Function

    ''' <summary>
    ''' 判断当前矩形与别的矩形是否有重合部分
    ''' </summary>
    ''' <param name="rec"></param>
    ''' <returns>布尔类型</returns>
    Public Function HasCrossArea(rec As ClsRectangle) As Boolean
        If rec.LeftBtm.PointRelation2Rectangle(Me) = 点与封闭图形的位置关系.在外部 And
            rec.LeftTop.PointRelation2Rectangle(Me) = 点与封闭图形的位置关系.在外部 And
            rec.RightBtm.PointRelation2Rectangle(Me) = 点与封闭图形的位置关系.在外部 And
            rec.RightTop.PointRelation2Rectangle(Me) = 点与封闭图形的位置关系.在外部 Then
            Return False
        Else
            Return True
        End If
    End Function

#End Region

End Class


